package my.netty.channel.nio;

import my.netty.channel.EventLoop;
import my.netty.channel.EventLoopGroup;
import my.netty.channel.ServerChannel;
import my.netty.channel.handler.ChannelInitializer;
import my.netty.exception.ChannelException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.SocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;

public class NioServerSocketChannel extends AbstractNioSocketChannel implements ServerChannel {

    private static final Logger log = LoggerFactory.getLogger(NioEventLoop.class);

    private final ServerSocketChannel serverSocketChannel;

    private final EventLoopGroup workerGroup;
    private final ChannelInitializer childHandler;

    public NioServerSocketChannel(EventLoopGroup workerGroup, ChannelInitializer childHandler) {
        try {
            this.serverSocketChannel = SelectorProvider.provider().openServerSocketChannel();
        } catch (IOException e) {
            throw new ChannelException("Failed to open a server socket.", e);
        }
        this.workerGroup = workerGroup;
        this.childHandler = childHandler;
    }

    @Override
    public void register(EventLoop eventLoop) {
        register(eventLoop, SelectionKey.OP_ACCEPT);
    }

    @Override
    public void accept() throws IOException {
        SocketChannel socketChannel = serverSocketChannel.accept();
        NioSocketChannel nioSocketChannel = new NioSocketChannel(socketChannel);
        childHandler.initChannel(nioSocketChannel);
        workerGroup.register(nioSocketChannel);
    }

    @Override
    public void bind(SocketAddress socketAddress) {
        try {
            serverSocketChannel.bind(socketAddress);
        } catch (Throwable e) {
            close();
            throw new ChannelException("bind", e);
        }
    }

    public ServerSocketChannel javaChannel() {
        return serverSocketChannel;
    }
}
